#include <CORBA.h>
#include "ggt_impl.h"
#include "Killer.h"
#include <coss/CosNaming.h>
#include <time.h>
#include <string.h>
#include <sstream>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <pthread.h>

using namespace std;
using namespace ggt;


CORBA::ORB_var orb;

void *happyKilling( void *aSlave )
{
	bool killed = false;
	ggt_impl *myslave = (ggt_impl*) aSlave;
	while(!killed){
		sleep(1);
		killed = myslave->tryToKill();
	}
	orb->shutdown(false);
}

// progName corba-specific[2] timeout verzoegerung slaveID
int main(int argc, char *argv[]) {
	int rc = 0;

	// Werte der Fehlerbehandlung
	bool killed = false;

	int timesOfRetry=5;
	int retrySleepingTime=2;
	int timeout = atoi(argv[3]);
	int sleepingtime = atoi (argv[4]);
	char *pidChar= argv[5];
	int myPID = atoi (pidChar);

	char *PIDName = new char[5/*slave*/ + 5/*00000<-ID*/ + 1/*\0*/];
	sprintf(PIDName, "slave%s", pidChar);

	cout << PIDName << " start" << endl;

	while (timesOfRetry!=0) {

		try {

			// init ORB
			orb = CORBA::ORB_init(argc, argv);

			CORBA::Object_var poaobj = orb -> resolve_initial_references("RootPOA");
			CORBA::Object_var nsobj = orb -> resolve_initial_references("NameService");

			PortableServer::POA_var poa = PortableServer::POA::_narrow (poaobj);

			PortableServer::POAManager_var mgr = poa->the_POAManager();

			//NARROW
			CosNaming::NamingContext_var nc = CosNaming::NamingContext::_narrow(nsobj);

			//COS Naming Name erzeugen
			CosNaming::Name name;
			name.length (1);
			//TODO: Name muss übergeben werden
			name[0].id = CORBA::string_dup (PIDName);
			name[0].kind = CORBA::string_dup ("");
			printf ("Erzeuge ggt::unit\n");

			//Einen SLAVE erzeugen
			ggt_impl *slave = new ggt_impl(argc, argv, nsobj,sleepingtime, myPID, timeout);

			//Objektreferenz erzeugen
			PortableServer::ObjectId_var oid = poa->activate_object (slave);
			CORBA::Object_var ref = poa->id_to_reference (oid.in());

			nc->rebind(name, ref);
			slave->helloChef();
			printf ("Running.\n");

			 pthread_t killerFred;
			 char *message1 = "Thread 1";
			 int  iret1;

			 /* Create independent threads each of which will execute function */

		     iret1 = pthread_create( &killerFred, NULL, happyKilling, (void*)slave);

		     /* Wait till threads are complete before main continues. Unless we (void*) message1  */
		     /* wait we run the risk of executing an exit which will terminate   */
		     /* the process and all threads before the threads have completed.   */

			mgr->activate ();
			orb->run();

			poa ->destroy(true, true);
			delete slave;
			rc = 0;
			break;
		}
		catch(CORBA::ORB::InvalidName_catch& ex)
		{
			ex->_print(cerr);
			cerr << endl;
			cerr << "possible cause: can't locate Naming Service\n";
			timesOfRetry--;
			sleep(retrySleepingTime);
			rc = 1;
		}
		catch(CosNaming::NamingContext::NotFound_catch& ex)
		{
			cerr << "Name not found at Naming Service\n";
			timesOfRetry--;
			sleep(retrySleepingTime);
			rc = 1;
		}
		catch(CORBA::SystemException_catch& ex)
		{
			ex->_print(cerr);
			cerr << endl;
			cout << "Noch " << timesOfRetry << " Verbindungsversuche"<< endl;
			timesOfRetry--;
			sleep(retrySleepingTime);
			rc = 1;
		}
	}
	return rc;

}

